﻿using CPPEI.Coolzon.Common;
using CPPEI.Coolzon.Designer.Event.UI;
using CPPEI.Coolzon.Designer.UI;
using CPPEI.Coolzon.Metadata;
using CPPEI.Coolzon.UI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Xceed.Wpf.AvalonDock.Layout;

namespace CPPEI.Coolzon.Designer.Views
{
    /// <summary>
    /// Interaction logic for MainView.xaml
    /// </summary>
    public partial class MainView : View
    {
        public readonly string SCENECONTENTID = "documentScene";
        private string _lastOpenedSceneId;
        public MainView()
        {
            InitializeComponent();

            Designer.Event.Core.CoreEventBus.Register(Designer.Views.EventProxy.Instance);
            Designer.Event.UI.UIEventBus.Register(Designer.Views.EventProxy.Instance);
            Designer.Event.NCL.NCLEventBus.Register(Designer.Views.EventProxy.Instance);

            Designer.Views.EventProxy.Instance.SetDesignView(_ctlDesignView);

            Designer.Event.UI.UIEventBus.Register(_ctlHeaderView);
            Designer.Event.UI.UIEventBus.Register(_ctlSolutionView);
            Designer.Event.NCL.NCLEventBus.Register(_ctlSolutionView);
            Designer.Event.UI.UIEventBus.Register(_ctlPropertyView);
            Designer.Event.UI.UIEventBus.Register(_ctlStatusView);
            Designer.Event.UI.UIEventBus.Register(_ctlEventView);
            Coolzon.UI.Designtime.EditorEventBus.Register(_ctlPropertyView);

            Designer.Event.UI.UIEventBus.Register(this);

            this._ctlHeaderView.Close += _ctlHeaderView_Close;

            this._ctlDesignView.SelectedChanged += _ctlDesignView_SelectedChanged;

            this._ctlDesignView.Added += _ctlDesignView_Added;

            this._ctlDesignView.Dirtied += _ctlDesignView_Dirtied;
            this._ctlDesignView.Closed += _ctlDesignView_Closed;
            this._ctlEventView.Dirtied += _ctlDesignView_Dirtied;

            UIContext.Current.CurrentDesignView = _ctlDesignView;
            UIContext.Current.DockingManager = _ctlDockingManager;

            // 组件结构树关联到设计试图上，DeattachDesignView用于释放关联
            this._ctlPartTree.AttachDesignView(_ctlDesignView);
            this._ctlStatusView.AttachDesignView(_ctlDesignView);
        }


        private void _ctlDesignView_Dirtied()
        {
            if (UIContext.Current.CurrentEditedNode != null && !UIContext.Current.CurrentEditedNode.Isdirty)
            {
                UIContext.Current.CurrentEditedNode.Isdirty = true;
            }
        }

        protected override void OnDestory()
        {
            Designer.Event.Core.CoreEventBus.Unregister(Designer.Views.EventProxy.Instance);
            Designer.Event.UI.UIEventBus.Unregister(Designer.Views.EventProxy.Instance);
            Designer.Event.NCL.NCLEventBus.Unregister(Designer.Views.EventProxy.Instance);
            Designer.Event.UI.UIEventBus.Unregister(_ctlSolutionView);
            Designer.Event.NCL.NCLEventBus.Unregister(_ctlSolutionView);
            Designer.Event.UI.UIEventBus.Unregister(_ctlPropertyView);
            Designer.Event.UI.UIEventBus.Unregister(_ctlStatusView);
            Designer.Event.UI.UIEventBus.Unregister(_ctlEventView);

            Designer.Event.UI.UIEventBus.Unregister(this);

            base.OnDestory();
        }
        void _ctlDesignView_Added(Coolzon.UI.Part part)
        {
            UIEventBus.Publish(new UIPartCreatedCompleteOrCancelEvent());
        }

        private void _ctlDesignView_SelectedChanged(Coolzon.UI.Part partInstance)
        {
            if (partInstance != null)
            {
                _ctlPropertyView.SelectPartChanged(partInstance);
                _ctlEventView.SelectPartChanged(partInstance);
                _ctlStatusView.SelectPartChanged(partInstance);
            }
        }
        private void _ctlDesignView_Closed(ScenePart scene)
        {
            _ctlPropertyView.Clear();
            _ctlEventView.Clear();
        }

        void _ctlHeaderView_Close(View view, bool isCancel)
        {
            Cancel();
        }

        public void SceneTabFocus(Guid itemId, string sceneName)
        {
            var _ctlScene = _ctlDockingManager.Layout.Descendents().OfType<LayoutDocument>().Single(a => a.ContentId == SCENECONTENTID);
            _ctlScene.Description = itemId.ToString();
            _ctlScene.Title = sceneName;
            _ctlScene.IsSelected = true;
        }

        public void OpenResource(SolutionTreeViewNode node, string fileName, ResourceType resourceType)
        {
            var firstDocumentPane = _ctlDockingManager.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
            if (firstDocumentPane != null && firstDocumentPane.ChildrenCount > 0)
            {
                foreach (var item in firstDocumentPane.Children)
                {
                    if (string.Equals((item as LayoutDocument).ContentId, node.ID.ToString()))
                    {
                        (item as LayoutDocument).IsSelected = true;
                        return;
                    }
                }
            }
            if (!string.IsNullOrWhiteSpace(fileName) && File.Exists(fileName))
            {
                LayoutDocument doc = new LayoutDocument();
                doc.Title = node.Name;
                doc.ContentId = node.ID.ToString();
                doc.Closing += Doc_Closing;
                doc.IsSelected = true;
                doc.CanClose = true;
                doc.CanFloat = false;

                if (resourceType == ResourceType.Image)
                {
                    BinaryReader binReader = new BinaryReader(File.Open(fileName, FileMode.Open));
                    FileInfo fileInfo = new FileInfo(fileName);
                    byte[] bytes = binReader.ReadBytes((int)fileInfo.Length);
                    binReader.Close();

                    // Init bitmap
                    BitmapImage image = new BitmapImage();
                    image.BeginInit();
                    image.StreamSource = new MemoryStream(bytes);
                    image.EndInit();

                    Image ctlImage = new Image();
                    ctlImage.Margin = new Thickness(3);
                    ctlImage.Stretch = Stretch.Fill;
                    ctlImage.Source = image;

                    doc.Content = ctlImage;
                    firstDocumentPane.Children.Add(doc);
                }
                else if (resourceType == ResourceType.Video)
                {
                    MediaElement mediaElement = new MediaElement();
                    mediaElement.LoadedBehavior = MediaState.Manual;
                    mediaElement.Stretch = Stretch.Fill;
                    mediaElement.Margin = new Thickness(3);
                    mediaElement.MediaEnded += (s, e1) =>
                    {
                        if (mediaElement != null)
                        {
                            mediaElement.Position = mediaElement.Position.Add(TimeSpan.FromMilliseconds(1));
                        }
                    };
                    mediaElement.Source = new Uri(fileName);
                    mediaElement.Play();

                    doc.Content = mediaElement;
                    firstDocumentPane.Children.Add(doc);
                }
                else if (resourceType == ResourceType.Js || resourceType == ResourceType.Txt || resourceType == ResourceType.Xml)
                {
                    string fileExt = string.Empty;
                    if (resourceType == ResourceType.Js)
                    {
                        fileExt = ".js";
                    }
                    else if (resourceType == ResourceType.Xml)
                    {
                        fileExt = ".xml";
                    }
                    else
                    {
                        fileExt = ".txt";
                    }
                    JSEditor editor = new JSEditor(node);
                    editor.OpenFile(fileName, fileExt);

                    doc.Content = editor;
                    firstDocumentPane.Children.Add(doc);
                }
            }
        }

        private void _ctlScene_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (SolutionTreeViewNodeHelper.IsCancelSaveOrUnSaveCurrentSceneOperation())
            {
                e.Cancel = true;
                return;
            }
            UIContext.Current.CurrentDesignView.API_Reset();
            ResetOpenSceneTitle();
            e.Cancel = true;
        }

        private void Doc_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            var document = sender as LayoutDocument;
            if (document != null && document.Content is JSEditor)
            {
                if ((document.Content as JSEditor).IsDirty)
                {
                    MessageBoxResult result = MessageBox.Show("存在未保存的项,是否保存？", "提示", MessageBoxButton.YesNoCancel, MessageBoxImage.Question, MessageBoxResult.Yes);
                    if (result == MessageBoxResult.Yes)
                    {
                        (document.Content as JSEditor).Save();
                    }
                    else if (result == MessageBoxResult.Cancel)
                    {
                        e.Cancel = true;
                        return;
                    }
                }
            }
        }

        private void _ctlTabControl_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            //var tabItem = VisualUpwardSearch<TabItem>(e.OriginalSource as DependencyObject) as TabItem;
            //if (tabItem != null)
            //{
            //    _ctlTabControl.SelectedItem = tabItem;
            //    e.Handled = true;
            //}
        }
        static DependencyObject VisualUpwardSearch<T>(DependencyObject source)
        {
            while (source != null && source.GetType() != typeof(T))
                source = VisualTreeHelper.GetParent(source);

            return source;
        }

        private void View_Loaded(object sender, RoutedEventArgs e)
        {
            OnLoadLayout();
        }

        [Common.Subscribe]
        public void OnOpenSolution(UICloseSolutionEvent @event)
        {
            _ctlDesignView.API_Reset();
            Dispatcher.Invoke(() =>
            {
                ResetOpenSceneTitle();
            });
        }

        private void ResetOpenSceneTitle()
        {
            var _ctlScene = _ctlDockingManager.Layout.Descendents().OfType<LayoutDocument>().Single(a => a.ContentId == SCENECONTENTID);
            _ctlScene.Title = "场景";
            if(_ctlScene.Description != null)
            {
                _lastOpenedSceneId = _ctlScene.Description;
                _ctlScene.Description = null;
            }
            _ctlScene.IsSelected = true;
        }

        public void UndoPendingChange()
        {
            var firstDocumentPane = _ctlDockingManager.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
            List<TabItem> removeItems = new List<TabItem>();
            List<SolutionTreeViewNode> keepItems = new List<SolutionTreeViewNode>();
            UIContext.Current.CurrentDesignView.API_Reset();
            for (int i = 0; i < firstDocumentPane.ChildrenCount; i++)
            {
                var item = firstDocumentPane.Children[i];
                Guid itemId;
                Tuple<bool, SolutionTreeViewNode> res;
                if (Guid.TryParse(item.ContentId, out itemId))
                {
                    res = FindTreeNode(UIContext.Current.SolutionNode, itemId);
                    if (!res.Item1)
                    {
                        item.Close();
                        i--;
                    }
                }
                else if (string.Equals(item.ContentId, SCENECONTENTID))
                {
                    if (Guid.TryParse(_lastOpenedSceneId, out itemId))
                    {
                        res = FindTreeNode(UIContext.Current.SolutionNode, itemId);
                        if (!res.Item1)
                        {
                            continue;
                        }
                        SolutionTreeViewNode node = res.Item2;

                        if (node.NodeType == NodeType.Scene)
                        {
                            if (UIContext.Current.CurrentEditedNode != null)
                            {
                                UIContext.Current.CurrentEditedNode.PropertyChanged -= SolutionView.CurrentEditedNode_PropertyChanged;
                            }
                            UIContext.Current.CurrentEditedNode = node;
                            UIContext.Current.CurrentEditedNode.PropertyChanged += SolutionView.CurrentEditedNode_PropertyChanged;
                            if (node.NodeStatus == NodeStatus.CheckIn || node.NodeStatus == NodeStatus.OthersLocked)
                            {
                                UIContext.Current.CurrentDesignView.API_OpenScene(node.Name, false);
                            }
                            else
                            {
                                UIContext.Current.CurrentDesignView.API_OpenScene(node.Name, true);
                            }
                            SceneTabFocus(node.ID, node.Name);
                            UIContext.Current.CurrentSelectedNode = node;
                        }
                    }
                }
            }
        }

        private Tuple<bool, SolutionTreeViewNode> FindTreeNode(SolutionTreeViewNode mode, Guid itemId)
        {
            Tuple<bool, SolutionTreeViewNode> res = new Tuple<bool, SolutionTreeViewNode>(false, null);
            if (mode.ID == itemId)
            {
                res = new Tuple<bool, SolutionTreeViewNode>(true, mode);
            }
            else
            {
                foreach (SolutionTreeViewNode cModel in mode.Children)
                {
                    res = FindTreeNode(cModel, itemId);
                    if (res.Item1) break;
                }
            }

            return res;
        }


        [Common.Subscribe]
        public void OnChangePartZIndex(UIChangePartZIndex @event)
        {
            _ctlPartTree.BringTreeViewItemTo(@event.PartName, @event.Index);
            if (UIContext.Current.CurrentEditedNode != null && !UIContext.Current.CurrentEditedNode.Isdirty)
            {
                UIContext.Current.CurrentEditedNode.Isdirty = true;
            }
        }

        /// <summary>
        /// 保存Docking布局
        /// </summary>
        public bool OnSaveLayout()
        {
            bool? isSave = null;
            //移除非场景document
            var firstDocumentPane = _ctlDockingManager.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
            if (firstDocumentPane != null)
            {
                for (int i = 0; i < firstDocumentPane.ChildrenCount; i++)
                {
                    var doc = firstDocumentPane.Children[i];
                    if (string.Equals(doc.ContentId, SCENECONTENTID))
                    {
                        doc.Title = "场景";
                        (doc as LayoutDocument).Description = null;
                    }
                    else
                    {
                        if (doc != null && doc.Content is JSEditor)
                        {
                            if ((doc.Content as JSEditor).IsDirty)
                            {
                                if (isSave == null)
                                {
                                    MessageBoxResult result = MessageBox.Show("存在未保存的项,是否保存？", "提示", MessageBoxButton.YesNoCancel, MessageBoxImage.Question, MessageBoxResult.Yes);
                                    if (result == MessageBoxResult.Yes)
                                    {
                                        isSave = true;
                                        (doc.Content as JSEditor).Save();
                                    }
                                    else if(result == MessageBoxResult.Cancel)
                                    {
                                        return false;
                                    }
                                }
                                else if (isSave.Value)
                                {
                                    (doc.Content as JSEditor).Save();
                                }
                            }
                        }
                        doc.Close();
                        i--;
                    }
                }
            }
            try
            {
                FileInfo fi = new FileInfo(AppDomain.CurrentDomain.BaseDirectory + @"\Profile\AvalonDock.config");
                if (!fi.Directory.Exists)
                {
                    fi.Directory.Create();
                }
                var serializer = new Xceed.Wpf.AvalonDock.Layout.Serialization.XmlLayoutSerializer(_ctlDockingManager);
                using (var stream = new StreamWriter(@".\Profile\AvalonDock.config"))
                    serializer.Serialize(stream);
            }
            catch(Exception ex)
            {
                Logger.ErrorToTag(Library.LogTAG, "加载AvalonDock.config错误:{0}", ex);
            }
            return true;
        }
        private void OnLoadLayout()
        {
            if (File.Exists(@".\Profile\AvalonDock.config"))
            {
                var serializer = new Xceed.Wpf.AvalonDock.Layout.Serialization.XmlLayoutSerializer(_ctlDockingManager);
                serializer.LayoutSerializationCallback += (s, args) =>
                    {
                        if (args.Model != null)
                        {
                            if (args.Model is LayoutAnchorable)
                            {
                                (args.Model as LayoutAnchorable).IsVisibleChanged += _ctlAnchorable_IsVisibleChanged;
                                UIEventBus.Publish(new UIAnchorableVisibleChangeEvent(args.Model.ContentId, (args.Model as LayoutAnchorable).IsVisible));
                            }
                            else if (args.Model is LayoutDocument && string.Equals((args.Model as LayoutDocument).ContentId, SCENECONTENTID))
                            {
                                (args.Model as LayoutDocument).IsSelectedChanged += MainViewSceneDocument_IsSelectedChanged;
                                (args.Model as LayoutDocument).Closing += _ctlScene_Closing;
                            }
                        }
                    };
                using (var stream = new StreamReader(@".\Profile\AvalonDock.config"))
                {
                    try
                    {
                        serializer.Deserialize(stream);
                    }
                    catch (Exception ex)
                    {
                        Logger.ErrorToTag(Library.LogTAG, "加载AvalonDock.config错误:{0}", ex);
                    }
                }
            }
        }

        private void MainViewSceneDocument_IsSelectedChanged(object sender, EventArgs e)
        {
            var sceneSocument = sender as LayoutDocument;
            if (!sceneSocument.IsSelected)
            {
                _ctlPropertyView.Clear();
                _ctlEventView.Clear();
                _ctlPartTree.SetVisible(false);
            }
            else
            {
                Coolzon.UI.Part part = _ctlDesignView.API_GetSelectedPart();
                if(part == null)
                {
                    part = _ctlDesignView.API_GetCurrentScenePart();
                }
                _ctlPropertyView.SelectPartChanged(part);
                _ctlEventView.SelectPartChanged(part);
                _ctlPartTree.SetVisible(true);
            }
        }

        private void _ctlAnchorable_IsVisibleChanged(object sender, EventArgs e)
        {
            var viewAnchorable = sender as LayoutAnchorable;
            UIEventBus.Publish(new UIAnchorableVisibleChangeEvent(viewAnchorable.ContentId, viewAnchorable.IsVisible));
        }
    }
}
